<?php

/*
 * Copyright (C) 2009 - 2011 Pham Cong Dinh
 *
 * This file is part of Spica.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

// namespace spica\core\session\store;

/**
 * This class provides Memcached storage backend for session data.
 *
 * @category   spica
 * @package    core
 * @subpackage session\store
 * @author     Pham Cong Dinh <pcdinh at phpvietnam dot net>
 * @since      Version 0.3
 * @since      April 15, 2010
 * @copyright  Pham Cong Dinh (http://www.phpvietnam.net)
 * @license    http://www.gnu.org/licenses/lgpl-3.0.txt
 * @version    $Id: Memcached.php 1869 2011-01-07 18:55:25Z pcdinh $
 */
class SpicaSessionMemcachedStore /* implements SpicaSessionStore */
{
    /**
     * Session lifetime.
     *
     * @var int
     */
    protected $_lifeTime;

    /**
     * Memcached driver.
     *
     * @var Memcache
     */
    protected $_driver;

    /**
     * Storage config.
     *
     * @var array
     */
    private $_config;

    /**
     * Constructs an object of <code>SpicaSessionMemcachedStore</code>.
     *
     * @param array $config Defaults to an empty array
     */
    public function __construct($config = array())
    {
        $default = array(
            'ip' => '127.0.0.1',
            'port' => 11211,
            'persistent' => false,
            'weight' => 1,
            'timeout' => 1,
            'retry_interval' => 3
        );

        if (true === empty($config))
        {
            $config = array(0 => array());
        }

        foreach ($config as $value)
        {
            $this->_config[] = array_merge($value, $default);
        }
    }

    /**
     * Opens session
     *
     * @param string $savePath ignored
     * @param string $sessName ignored
     * @return bool
     */
    public function open($savePath, $sessName)
    {
        $this->_lifeTime = ini_get('session.gc_maxlifetime');
        $this->_driver = new Memcache();

        foreach ($this->_config as $server)
        {
            $this->_driver->addServer($server['ip'], $server['port'], $server['persistent'], $server['weight'], $server['timeout'], $server['retry_interval']);
        }

        return true;
    }

    /**
     * Fetches session data
     *
     * @param  string $sid
     * @return string
     */
    public function read($sid)
    {
        $value = $this->_driver->get($sid);

        if (false !== $value)
        {
            if (($value['modified'] + $this->_lifeTime) > time())
            {
                return $value['data'];
            }

            $this->destroy($sid);
        }

        return '';
    }

    /**
     * Closes session
     *
     * @return bool
     */
    public function close()
    {
        if (null !== $this->_driver)
        {
            $this->_driver->close();
        }
    }

    /**
     * Updates session.
     *
     * @param  string $sid Session ID
     * @param  string $data
     * @return bool
     */
    public function write($sid, $data)
    {
        $data = array(
            'modified' => time(),
            'data' => $data
        );

        $value = $this->_driver->get($sid);

        if (false === $value)
        {
            $this->_increment(); // New session. Possibly
            return $this->_driver->add($sid, $data, MEMCACHE_COMPRESSED); // no expired - check on read
        }
        
        return $this->_driver->replace($sid, $data, MEMCACHE_COMPRESSED); // no expired - check on read
    }

    /**
     * Destroys session provided with ID.
     *
     * @param  string $sid
     * @return bool
     */
    public function destroy($sid)
    {
        $this->_decrement();
        return $this->_driver->delete($sid);
    }

    /**
     * Garbage collection
     *
     * @param  int $sessMaxLifeTime ignored
     * @return bool
     */
    public function gc($sessMaxLifeTime)
    {
        return true;
    }

    /**
     * Gets total session.
     *
     * @return int
     */
    public function getSessionCount()
    {
        return (int) $this->_driver->get('spica_total_session_count');
    }

    /**
     * Increments total session count.
     *
     * @return bool
     */
    protected function _increment()
    {
        $this->_driver->add('spica_total_session_count', '0', false);
        return $this->_driver->increment('spica_total_session_count', 1);
    }

    /**
     * Decreases total session count.
     *
     * @return bool
     */
    protected function _decrement()
    {
        return $this->_driver->decrement('spica_total_session_count', 1);
    }
}

?>